//
//  TMPlan.m
//  cutter
//
//  Created by mac on 15/12/30.
//  Copyright © 2015年 e360. All rights reserved.
//

#import "TMPlan.h"

@implementation TMPlanVertex
-(instancetype)initWithPoint:(CGPoint)point{
    self = [super init];
    if (self) {
        [self setPoint:point];
    }
    return self;
}
-(id<TMPlanElement>)hitTest:(TMPlanVertex*)vertex error:(CGFloat)error{
    CGPoint s = TMPointSubtract(self.point, vertex.point);
    if (TMPointDotProduct(s, s) <= error * error){
        [vertex setX:self.x];
        [vertex setY:self.y];
        return self;
    }
    return nil;
}
-(instancetype)clone{
    return [[TMPlanVertex alloc] initWithPoint:self.point];
}
-(void)setPoint:(CGPoint)point{
    [self setX:point.x];
    [self setY:point.y];
}
-(CGPoint)point{
    return CGPointMake(self.x, self.y);
}
@end


@implementation TMPlanFace
-(id<TMPlanElement>)hitTest:(TMPlanVertex*)vertex error:(CGFloat)error{
    return nil;
}
@end


@implementation TMPlanWall
-(id<TMPlanElement>)hitTest:(TMPlanVertex*)vertex error:(CGFloat)error{
    //点
    if ([self.from hitTest:vertex error:error] != nil || [self.to hitTest:vertex error:error] != nil){
        return self;
    }
    //边
    CGPoint q;
    CGPoint p = vertex.point;
    if (TMPointProject(self.from.point, self.to.point, p, &q)){
        CGPoint s = TMPointSubtract(p, q);
        if (TMPointDotProduct(s, s) <= error * error){
            [vertex setPoint:q];
            return self;
        }
    }
    return nil;
}
-(void)addDoor:(TMPlanDoor*)door{
    
}
-(void)delDoor:(TMPlanDoor*)door{
    
}
//
/*-(instancetype)init{
    self = [super init];
    if (self) {
        [self setVertexs:[NSMutableArray array]];
    }
    return self;
}
-(id<TMPlanElement>)hitTest:(TMPlanVertex*)vertex error:(CGFloat)error{
    TMPlanEdge *edge = [[TMPlanEdge alloc] init];
    for (uint i=1; i<self.vertexs.count; i++) {
        [edge setTo:[self.vertexs objectAtIndex:i]];
        [edge setFrom:[self.vertexs objectAtIndex:i - 1]];
        if ([edge hitTest:vertex error:error]){
            return self;
        }
    }
    return nil;
}
-(void)merge:(TMPlanWall*)other{
    CGFloat u = 0;
    CGFloat v = 0;
    CGPoint p = CGPointMake(0, 0);
    //
    for (uint i=1; i<self.vertexs.count; i++) {
        for (uint j=1; i<other.vertexs.count; j++) {
            TMPlanVertex *sc = [self.vertexs objectAtIndex:i];
            TMPlanVertex *oc = [other.vertexs objectAtIndex:j];
            TMPlanVertex *sp = [self.vertexs objectAtIndex:i - 1];
            TMPlanVertex *op = [other.vertexs objectAtIndex:j - 1];
            if (TMPointIntersect(sp.point, sc.point, op.point, oc.point, &p, &u, &v)) {
                if ((u == 1 || u == 0) && (v == 0 || v == 1)){
                    continue;
                }
                TMPlanVertex *ip = [[TMPlanVertex alloc] initWithPoint:p];
                if (u > 0 && u < 1){
                    NSMutableArray *tmp = [NSMutableArray arrayWithArray:self.vertexs];
                    [tmp insertObject:ip atIndex:i];
                    [self setVertexs:tmp];
                    [ip setType:1];
                }
                if (v > 0 && v < 1){
                    NSMutableArray *tmp = [NSMutableArray arrayWithArray:other.vertexs];
                    [tmp insertObject:ip atIndex:j];
                    [other setVertexs:tmp];
                    [ip setType:1];
                }
            }
        }
    }
}*/
@end


//
@implementation TMPlanRoom
-(id<TMPlanElement>)hitTest:(TMPlanVertex*)vertex error:(CGFloat)error{
    /*
    //内部
    uint n = 0;
    CGPoint f = vertex.point;
    CGPoint t = CGPointMake(f.x, CGFLOAT_MAX);
    for (uint i=1; i<self.vertexs.count; i++) {
        TMPlanVertex *sc = [self.vertexs objectAtIndex:i];
        TMPlanVertex *sp = [self.vertexs objectAtIndex:i - 1];
        if (TMPointIntersect(sp.point, sc.point, f, t, NULL, NULL, NULL)) {
            n++;
        }
    }
    if (n % 2 == 1){
        return self;
    }
    //边点
    if ([super hitTest:vertex error:error]) {
        return self;
    }*/
    return nil;
}
@end
//


@interface TMPlan ()
@property(assign, nonatomic) CGFloat error;
@property(strong, nonatomic) NSMutableArray *walls;
@property(strong, nonatomic) NSMutableArray *areas;
//
@property(strong, nonatomic) TMPlanWall *wall;
@end
@implementation TMPlan
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setWalls:[NSMutableArray array]];
        [self setError:15];
    }
    return self;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self setWall:[self makeWall:[[touches anyObject] locationInView:self]]];
    [self.walls addObject:self.wall];
    [self setNeedsDisplay];
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if (self.wall != nil) {
        TMPlanVertex *v = self.wall.to;
        if (v) {
            CGPoint p = [[touches anyObject] locationInView:self];
            /*for (TMLine *l in self.lines){
                for (TMVertex *t in l.vertexs){
                    if (t != v){
                        if (fabs(p.x - v.x) <= self.error * 0.5){
                            p.x = v.x;
                        }
                        if (fabs(p.y - v.y) <= self.error * 0.5){
                            p.y = v.y;
                        }
                    }
                }
                //
                TMVertex *t = [[TMVertex alloc] initWithPoint:p];
                if ([l hitTest:t error:self.error] != nil) {
                    p.x = t.x;
                    p.y = t.y;
                }
            }*/
            [v setPoint:p];
            [self setNeedsDisplay];
        }
    }
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if (self.wall != nil) {
        TMPlanVertex *v = [[TMPlanVertex alloc] initWithPoint:[[touches anyObject] locationInView:self]];
        if ([self.wall hitTest:v error:self.error]) {
            if (TMPointEquals(v.point, self.wall.from.point)) {
                [self.wall setFrom:v];
            }
            if (TMPointEquals(v.point, self.wall.to.point)) {
                [self.wall setTo:v];
            }
            [self setWall:nil];
        }
        //
        NSArray *vertexs = [self mergeVertex];
        [self findAreas:vertexs];
        [self setNeedsDisplay];
    }
}
-(void)drawRect:(CGRect)rect{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0, 0);
    CGContextRotateCTM(context, 0);
    //wall
    CGContextSetLineWidth(context, 24);
    CGContextSetStrokeColorWithColor(context, [[UIColor darkGrayColor] CGColor]);
    for (TMPlanWall *w in self.walls) {
        CGContextMoveToPoint(context, w.from.x, w.from.y);
        CGContextAddLineToPoint(context, w.to.x, w.to.y);
    }
    CGContextDrawPath(context, kCGPathStroke);
    //area
    CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
    for (NSArray *l in self.areas) {
        for (uint i=0;i<l.count;i++) {
            TMPlanVertex *v = [l objectAtIndex:i];
            if (i==0) {
                CGContextMoveToPoint(context, v.x, v.y);
            }else{
                CGContextAddLineToPoint(context, v.x, v.y);
            }
        }
    }
    CGContextDrawPath(context, kCGPathFill);
}
//颠倒数组
-(void)reverse:(NSMutableArray*)array{
    for(NSInteger i = 0, j = array.count-1; i < j; i++, j--){
        id lef = [array objectAtIndex:i];
        id rig = [array objectAtIndex:j];
        [array replaceObjectAtIndex:i withObject:rig];
        [array replaceObjectAtIndex:j withObject:lef];
    }
}
-(TMPlanWall*)makeWall:(CGPoint)point{
    TMPlanVertex *v = [[TMPlanVertex alloc] initWithPoint:point];
    //
    TMPlanWall *w = [self pickWall:v ignore:nil];
    if (w != nil) {
        if (TMPointEquals(v.point, w.from.point)) {
            v = w.from;
        }else if (TMPointEquals(v.point, w.to.point)) {
            v = w.to;
        }else{
            [w hitTest:v error:self.error];
        }
    }
    //
    w = [[TMPlanWall alloc] init];
    [w setTo:[v clone]];
    [w setFrom:v];
    return w;
}
-(TMPlanWall*)pickWall:(TMPlanVertex*)vertex ignore:(TMPlanWall*)ignore{
    for (TMPlanWall *w in self.walls) {
        if (w != ignore && [w hitTest:vertex error:self.error]) {
            return w;
        }
    }
    return nil;
}
//合并点
-(NSArray*)mergeVertex{
    NSMutableArray *vertexs = [NSMutableArray array];
    for (TMPlanWall *w in self.walls) {
        for (TMPlanVertex *s in vertexs){
            if (TMPointEquals(s.point, w.from.point)){
                [vertexs addObject:s];
                [w setFrom:s];
                break;
            }
        }
        for (TMPlanVertex *s in vertexs){
            if (TMPointEquals(s.point, w.to.point)){
                [vertexs addObject:s];
                [w setTo:s];
                break;
            }
        }
    }
    return [NSArray arrayWithArray:vertexs];
}
-(void)findAreas:(NSArray*)vertexs{
    [self setAreas:[NSMutableArray array]];
    //有效线段
    NSMutableDictionary *adj = [NSMutableDictionary dictionary];
    for (TMPlanWall *l in self.walls) {
        TMPlanVertex *a = l.to;
        TMPlanVertex *b = l.from;
        //
        NSNumber *ka = [NSNumber numberWithUnsignedInteger:[vertexs indexOfObject:a]];
        NSMutableArray *aa = [adj objectForKey:ka];
        if (aa == nil) {
            aa = [NSMutableArray array];
            [adj setObject:aa forKey:ka];
        }
        [aa addObject:b];
        //
        NSNumber *kb = [NSNumber numberWithUnsignedInteger:[vertexs indexOfObject:b]];
        NSMutableArray *ab = [adj objectForKey:kb];
        if (ab == nil) {
            ab = [NSMutableArray array];
            [adj setObject:ab forKey:kb];
        }
        [ab addObject:a];
    }
    for (NSNumber *k in adj.allKeys) {
        NSArray *v = [adj objectForKey:k];
        if (v.count < 2) {
            [adj removeObjectForKey:k];
        }
    }
    for (TMPlanWall *l in self.walls) {
        TMPlanVertex *a = l.to;
        TMPlanVertex *b = l.from;
        if ([vertexs indexOfObject:a] != NSNotFound && [vertexs indexOfObject:b] != NSNotFound) {
            [self walkStep:[NSMutableArray arrayWithObjects:a, b, nil] vertexs:vertexs];
        }
    }
}
-(void)walkStep:(NSMutableArray*)path vertexs:(NSArray*)vertexs{
    TMPlanVertex *vl = [path lastObject];
    TMPlanVertex *vf = [path firstObject];
    if (NO == TMPointEquals(vf.point,vl.point)) {
        NSMutableArray *nextPath = [NSMutableArray array];
        for (TMPlanWall *l in self.walls) {
            TMPlanVertex *va = l.to;
            TMPlanVertex *vb = l.from;
            if ([vertexs indexOfObject:va] != NSNotFound && [vertexs indexOfObject:vb] != NSNotFound) {
                if (TMPointEquals(va.point,vl.point)) {
                    [nextPath addObject:vb];
                }
                if (TMPointEquals(vb.point,vl.point)) {
                    [nextPath addObject:va];
                }
            }

        }
        //
        CGFloat angle = 0;
        TMPlanVertex *vi = nil;
        TMPlanVertex *va = path[path.count - 2];
        TMPlanVertex *vb = path[path.count - 1];
        for (TMPlanVertex *vc in nextPath){
            if (vc != va){
                if (vi == nil){
                    angle = TMPointAngle(va.point, vb.point, vc.point);
                    vi = vc;
                }else{
                    CGFloat ta = TMPointAngle(va.point, vb.point, vc.point);
                    if(ta < angle){
                        angle = ta;
                        vi = vc;
                    }
                }
            }
        }
        if (vi != nil){
            if (TMPointEquals(vf.point, vi.point)){
                [self.areas addObject:path];
            }else{
                [path addObject:vi];
                [self walkStep:path vertexs:vertexs];
            }
        }
    }
}
@end
